/*
    This file is part of Posixcpp library.

    Posixcpp library is free software: you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public License
    as published by the Free Software Foundation, either version 3 of
    the License, or (at your option) any later version.

    Posixcpp library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU LesserGeneral Public
    License along with Posixcpp library. If not, see
    <http://www.gnu.org/licenses/>.
 */

/**
 * @file posixcpp_bytearray.hpp
 * @brief ByteArray char buffer wrapper declarations
 */

#ifndef POSIXCPP_CONTAINERS_BYTEARRAY_HPP_INCLUDED
#define POSIXCPP_CONTAINERS_BYTEARRAY_HPP_INCLUDED

#include <string>

#include "posixcpp.hpp"

namespace posixcpp
{

/**
 * Byte array with the ability to wrap a C array
 */
class ByteArray
{
public:
    /**
     * @brief Constructs NULL array
     */
    ByteArray();
    /**
     * @brief Copy constructor with memory allocation and copying
     */
    ByteArray(const ByteArray & other);
    /**
     * @brief assignment operator, copying data     * 
     * @param other instance
     * @return 
     */
    ByteArray & operator=(const ByteArray & other);
    /**
     * @brief Copy by swap
     */
    ByteArray(const ByteArray && other);
    /**
     * Filling constructor. Memory allocation occured
     *
     * @param size  Array size
     * @param fillChar Byte to fill with
     */
    ByteArray(size_t size, uint8_t fillChar = uint8_t(0U));
    /**
     * Constructor with memory allocation and copying of the existing data buffer
     *
     * @param data  Start address of memory region
     * @param size  Bytes to copy
     */
    ByteArray(const uint8_t * data, size_t size);
    /**
     * @brief d-tor
     */
    virtual ~ByteArray();
    /**
     * Returns, if exists, ByteArray owning wrapper instance pointer for
     * given char buffer
     * 
     * @param data char buffer, owned by ByteArray
     * @return pointer to instance or NULL if not exists
     */
    static ByteArray* wrapper(uint8_t *data) {
        return *reinterpret_cast<ByteArray**>(data-sizeof(ByteArray*));
    }
    /**
     * Overloaded version
     */
    static const ByteArray* wrapper(const uint8_t *data);
    /**
     * Make array NULL. Frees data if owning.
     */
    void clear();
    /**
     * Fill part of the array with byte
     *
     * @param byte Byte to fill with
     * @param start	Starting position
     * @param count	Size of the filled fragment. 0 means filling until end
     */
    void fill(uint8_t byte = uint8_t(0), size_t start = 0, size_t count = 0);
    /**
     * Copy existing memory area. Memory allocation occures if needed.
     * Object owns data as a result
     *
     * @param data  start address
     * @param size  size
     */
    void copyExistingData(const uint8_t * data, size_t size);
    /**
     * Resize the array. Memory allocation occures if nedded
     *
     * @param newSize New reserved memory size
     */
    void resize(size_t newSize);
    /**
     * Reserve memory for future size grow
     * Affects capacity property, with cannot be decreased although

     * @param newSize New reserved memory size.
     */
    void reserve(size_t newCapacity);
    /**
     * Decreases the capacity if size is less then it
     */
    void compact();
    /**
     * Wrap existing memory area without any allocations
     * Object does not owns data and will not free memory in any case
     */
    void wrapExistingData(uint8_t * data, size_t size);

    bool ownsData() const {
        return m_ownsData;
    }

    size_t size() const {
        return m_size;
    }

    size_t capacity() const {
        return m_capacity;
    }

    uint8_t * data();

    const uint8_t * data() const;

    std::string toHex(uint8_t rowSize = 0) const;
    std::string toBin(uint8_t rowSize = 0) const;

    uint8_t & operator[](size_t pos);

    uint8_t operator[](size_t pos) const;
    
    uint8_t at(size_t pos) const;

    bool isEmpty() const {
        return m_size == 0;
    }

    bool isNull() const {
        return m_data == NULL;
    }

private:
    /**
     * Flag of the ownership of the data buffer
     */
    bool m_ownsData;
    /**
     * Pointer to the buffer
     */
    uint8_t * m_data;
    /**
     * size of the buffer
     */
    size_t m_size;
    /**
     * Allocated size
     */
    size_t m_capacity;
};

}
#endif // POSIXCPP_CONTAINERS_BYTEARRAY_HPP_INCLUDED
